# @rspress/plugin-llms <SourceCode href="https://github.com/web-infra-dev/rspress/tree/main/packages/plugin-llms" />

import { SourceCode } from '@rspress/core/theme';

为 Rspress 站点生成 [llms.txt](https://llmstxt.org/) 相关文件，使大模型可以更好地理解你的文档站。

## 安装

import { PackageManagerTabs } from '@theme';

<PackageManagerTabs command="add @rspress/plugin-llms -D" />

## 使用

### 1. 安装插件

在配置文件中写入以下的配置：

```ts
// rspress.config.ts
import { defineConfig } from '@rspress/core';
import { pluginLlms } from '@rspress/plugin-llms';

export default defineConfig({
  plugins: [pluginLlms()],
});
```

之后执行 `rspress build` 命令，在生成产物的同时，会在产物目录下根据导航栏、侧边栏生成 `llms.txt` `llms-full.txt` 和对应路由的 markdown 文件。

### 2. UI 展示

如果你希望阅读文档站的用户可以更多地调用大模型来阅读文档，可以通过 [自定义主题](/ui/custom-theme) 在页面顶部增加一个复制 Markdown 按钮，效果与本网站相同。

为所有页面增加顶部复制按钮，示例：

```tsx title="theme/index.tsx"
import { getCustomMDXComponent as basicGetCustomMDXComponent } from '@rspress/core/theme';
import {
  LlmsContainer,
  LlmsCopyButton,
  LlmsViewOptions,
} from '@rspress/plugin-llms/runtime';

function getCustomMDXComponent() {
  const { h1: H1, ...mdxComponents } = basicGetCustomMDXComponent();

  const MyH1 = ({ ...props }) => {
    return (
      <>
        <H1 {...props} />
        {/* [!code highlight:5] */}
        <LlmsContainer>
          <LlmsCopyButton />
          {/* LlmsViewOptions 组件可根据需要添加  */}
          <LlmsViewOptions />
        </LlmsContainer>
      </>
    );
  };
  return {
    ...mdxComponents,
    h1: MyH1,
  };
}

export { getCustomMDXComponent };
export * from '@rspress/core/theme';
```

为指定页面增加复制按钮，示例：

```mdx title="docs/hello-world.mdx"
# Hello world

<LlmsContainer>
  <LlmsCopyButton />
  <LlmsViewOptions /> {/* LlmsViewOptions 组件可根据需要添加  */}
</LlmsContainer>

这是一个示例文档。
```

## 选项

这个插件接受一个对象参数，类型如下:

- **类型**:

<details>

```ts
interface LlmsTxt {
  name: string;
  onTitleGenerate?: (context: {
    title: string | undefined;
    description: string | undefined;
  }) => string;
  onLineGenerate?: (page: PageIndexInfo) => string;
  onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
}

interface MdFiles {
  mdxToMd?: boolean;
  remarkPlugins?: PluggableList;
}

interface LlmsFullTxt {
  name: string;
}
export interface Options {
  llmsTxt?: false | LlmsTxt;
  mdFiles?: false | MdFiles;;
  llmsFullTxt?: false | LlmsFullTxt;
  include?: (context: { page: PageIndexInfo }) => boolean;
  exclude?: (context: { page: PageIndexInfo }) => boolean;
}
```

</details>

- **默认值**:

当未开启 [国际化](/guide/default-theme/i18n) 时，默认值为:

```ts
{
  llmsTxt: { name: 'llms.txt' },
  llmsFullTxt: { name: 'llms-full.txt' },
  mdFiles: true
}
```

当开启 [国际化](/guide/default-theme/i18n) 时，会使用[多组配置](#group)，默认值为:

```ts
[
  {
    llmsTxt: { name: 'llms.txt' },
    llmsFullTxt: { name: 'llms-full.txt' },
    mdFiles: true,
    include: ({ page }) => page.lang === config.lang,
  },
  // 根据 locales 配置自动生成其他语言
  {
    llmsTxt: { name: `${lang}/llms.txt` },
    llmsFullTxt: { name: `${lang}/llms-full.txt` },
    mdFiles: true,
    include: ({ page }) => page.lang === lang,
  },
  // ...
];
```

### llmsTxt

- **类型**: `false | LlmsTxt`

```ts
import type { PageIndexInfo } from '@rspress/core';

export interface LlmsTxt {
  name: string;
  onTitleGenerate?: (context: {
    title: string | undefined;
    description: string | undefined;
  }) => string;
  onLineGenerate?: (page: PageIndexInfo) => string;
  onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
}
```

- **默认值**: `{ name: 'llms.txt' }`

是否生成 llms.txt 文件，或者通过 hooks 自定义生成 llms.txt 文件。

一个 llms.txt 文件的默认格式如下：

```markdown
# {title}

> {description}

## {nav1.title}

- [{page.title}]({ page.routePath }): {page.frontmatter.description}

## {nav2.title}

- [{page.title}]({ page.routePath }): {page.frontmatter.description}
```

你可以通过 hook 对指定部分进行修改。

- `onTitleGenerate`: 自定义生成 title 和 description 部分。
- `onLineGenerate`: 自定义生成 md 文件的每一行。
- `onAfterLlmsTxtGenerate`: 最后修改 llms.txt 文件的内容。

例如：

```ts
pluginLlms({
  llmsTxt: {
    onTitleGenerate: ({ title, description }) => {
      return `# ${title} - llms.txt

> ${description}

Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.
`;
    },
  },
});
```

对应的生成结果为：

```markdown
# Rspress - llms.txt

> Rsbuild based static site generator

Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.

## guide

- [foo](/foo.md)
```

### mdFiles

- **类型**: `false | MdFiles`

```ts
export interface MdFiles {
  mdxToMd?: boolean;
  remarkPlugins?: PluggableList;
}
```

- **默认值**: `{ mdxToMd: false, remarkPlugins: [] }`

是否生成对应路由的 markdown 文件，当设置为 `false` 时，不会生成对应路由的 markdown 文件。

#### mdxToMd

- **类型**: `boolean`
- **默认值**: `false`

是否将 mdx 内容转换为 md 内容，如果启用，会将 mdx 文件通过一组默认策略转换为 md 文件，但可能会有一定的信息丢失。

#### remarkPlugins

- **类型**: `PluggableList`
- **默认值**: `[]`

用户可以传入自定义的 remark plugins 来对 Markdown 的内容做一些修改。

### llmsFullTxt

- **类型**: `false | LlmsFullTxt`

```ts
export interface LlmsFullTxt {
  name: string;
}
```

- **默认值**: `{ name: 'llms-full.txt' }`

是否生成 llms-full.txt 文件，当设置为 `false` 时，不会生成 `llms-full.txt` 文件。

### include

- **类型**: `(context: { page: PageIndexInfo }) => boolean`

是否生成时包含某些页面，一般用于精简 llms.txt。

- 示例：

只为语言为英文的页面生成 `llms.txt` 等相关文件：

```ts
pluginLlms({
  llmsTxt: {
    name: 'llms.txt',
  },
  llmsFullTxt: {
    name: 'llms-full.txt',
  },
  include: ({ page }) => {
    return page.lang === 'en';
  },
});
```

### exclude

- **类型**: `(context: { page: PageIndexInfo }) => boolean`

是否生成时排除某些页面，会在 `include` 之后执行。

- 示例：

排除 `/foo` 路由下的单个页面：

```ts
pluginLlms({
  llmsTxt: {
    name: 'llms.txt',
  },
  llmsFullTxt: {
    name: 'llms-full.txt',
  },
  exclude: ({ page }) => {
    return page.routePath === '/foo';
  },
});
```

## UI 组件选项

### LlmsCopyButtonProps

- **类型**：`LlmsCopyButtonProps`

```ts
interface LlmsCopyButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  textByLang?: Record<string, string>;
  text?: string;
}
```

#### textByLang

- **类型**：`Record<string, string>`
- **默认值**：`{ en: 'Copy Markdown', zh: '复制 Markdown' }`

根据对应语言替换按钮上的文本。

- **示例**：

```mdx
<LlmsCopyButton textByLang={{ en: 'Copy MD' }} />
```

#### text

- **类型**：`string`
- **默认值**：`''`

复制按钮上的文本，优先级比 `textByLang` 高。

### LlmsViewOptionsProps

- **类型**：`LlmsViewOptionsProps`

```ts
type Option =
  | {
      title: string;
      icon?: React.ReactNode;
      onClick?: () => void;
    }
  | {
      title: string;
      href: string;
      icon?: React.ReactNode;
    }
  | 'markdownLink'
  | 'chatgpt'
  | 'claude';

interface LlmsViewOptionsProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  options?: Option[];
  textByLang?: Record<string, string>;
  text?: string;
}
```

#### options

- **类型**：`Option[]`

```ts
type Option =
  | {
      title: string;
      icon?: React.ReactNode;
      onClick?: () => void;
    }
  | {
      title: string;
      href: string;
      icon?: React.ReactNode;
    }
  | 'markdownLink'
  | 'chatgpt'
  | 'claude';
```

- **默认值**：`['markdownLink', 'chatgpt', 'claude']`

自定义下拉菜单中的选项，默认支持 “复制 Markdown 链接”、[Chatgpt](https://chatgpt.com/) 和 [Claude](https://claude.ai)。

#### textByLang

- **类型**：`Record<string, string>`
- **默认值**：`{ en: 'Open', zh: '打开' }`

根据对应语言替换按钮上的文本。

#### text

- **类型**：`string`
- **默认值**：`''`

按钮上的文本，优先级比 `textByLang` 高。

## 同时生成多组 `llms.txt` \{#group}

某些情况下，你可能生成多组 `llms.txt`，例如多语言站点。此时，你可以通过传入一个数组来实现。

- 示例：

```ts
// rspress.config.ts
import { defineConfig } from '@rspress/core';
defineConfig({
  lang: 'en',
  plugins: [
    pluginLlms([
      {
        llmsTxt: {
          name: 'llms.txt',
        },
        llmsFullTxt: {
          name: 'llms-full.txt',
        },
        include: ({ page }) => page.lang === 'en',
      },
      {
        llmsTxt: {
          name: 'zh/llms.txt',
        },
        llmsFullTxt: {
          name: 'zh/llms-full.txt',
        },
        include: ({ page }) => page.lang === 'zh',
      },
    ]),
  ],
});
```
